package com.watson.zookeeperdemo;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.watson.zookeeperdemo.config.ZkStrSerializer;
import com.watson.zookeeperdemo.dbconfig.JDBCConfig;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.I0Itec.zkclient.IZkDataListener;
import org.I0Itec.zkclient.ZkClient;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * https://blog.csdn.net/fanfan4569/article/details/108315326
 *
 * @author AdminWatson
 */
@SpringBootApplication
public class ZookeeperApplication {
    private static HikariDataSource hikariDataSource;
    private static ZkClient zkClient;
    private static ObjectMapper mapper = new ObjectMapper();

    public static void main(String[] args) {
        SpringApplication.run(ZookeeperApplication.class, args);
        initZk();
        configHikariSource();
    }


    private static void initZk() {
        zkClient = new ZkClient("192.168.43.112:2181");
        zkClient.setZkSerializer(new ZkStrSerializer());
        zkClient.subscribeDataChanges("/jdbc", new IZkDataListener() {
            @Override
            public void handleDataChange(String path, Object data) {
                System.out.println(path + " data is changed, new data " + data);
                hikariDataSource.close();
                configHikariSource();
            }

            @Override
            public void handleDataDeleted(String path) {
                System.out.println(path + " is deleted!!");
                hikariDataSource.close();
            }
        });
    }

    /**
     * 配置数据库连接池
     * <p>
     * 1. 从 zookeeper 中获取配置信息
     * 2. 更新 hikari 配置
     * 3. 执行测试 sql
     */
    private static void configHikariSource() {
        JDBCConfig myConfig = getJDBCConfig();
        System.out.println("configHikariSource=============");
        updateHikariConfig(myConfig);
        try {
            executeTestSQL();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        System.out.println("configHikariSource2222=============");
    }

    private static void executeTestSQL() throws SQLException {
        Connection connection = hikariDataSource.getConnection();
        PreparedStatement pst = connection.prepareStatement("SELECT id, username FROM user;");
        ResultSet rs = pst.executeQuery();
        while (rs.next()) {
            System.out.println("id : " + rs.getString(1) + " , username : " + rs.getString(2));
        }
        System.out.println("executeTestSQL=============");
    }

    private static void updateHikariConfig(JDBCConfig myConfig) {
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl(myConfig.getUrl());
        config.setUsername(myConfig.getUsername());
        config.setPassword(myConfig.getPassword());
        config.addDataSourceProperty("driverClassName", myConfig.getDriver());
        config.addDataSourceProperty("cachePrepStmts", "true");
        config.addDataSourceProperty("prepStmtCacheSize", "250");
        config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
        hikariDataSource = new HikariDataSource(config);
    }

    private static JDBCConfig getJDBCConfig() {
        /**
         * zk中创建节点
         * create /jdbc {"url":"jdbc:mysql://localhost:3306/test?useUnicode=true&useSSL=false","username":"root","password":"root","driver":"com.mysql.jdbc.Driver"}
         *
         * 更改：
         * 驱动：改变为 com.mysql.cj.jdbc.Driver
         * 因为 mysql 版本使用 8.0
         * set /jdbc {"url":"jdbc:mysql://localhost:3306/test?useUnicode=true&useSSL=false","username":"root","password":"root","driver":"com.mysql.cj.jdbc.Driver"}
         *
         * 删除节点
         * delete /jdbc
         */
        Object data = zkClient.readData("/jdbc");
        try {
            JDBCConfig myConfig = mapper.readValue(data.toString(), JDBCConfig.class);
            System.out.println("getJDBCConfig====" + myConfig.toString());
            return myConfig;
        } catch (JsonProcessingException e) {
            return new JDBCConfig();
        }
    }
}

